package tms.util.jsf;

import tms.util.constants.NavigationConstant;
import tms.util.exception.ApplicationRuntimeException;
import tms.util.logging.LoggingManager;

import javax.el.ELException;
import javax.faces.FacesException;
import javax.faces.application.ViewExpiredException;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.event.ExceptionQueuedEvent;
import javax.faces.event.ExceptionQueuedEventContext;
import java.util.Iterator;

public class CustomExceptionExceptionHandler extends ExceptionHandlerWrapper {

    private ExceptionHandler wrapped;

    public CustomExceptionExceptionHandler(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public ExceptionHandler getWrapped() {
        return this.wrapped;
    }

    @Override
    public void handle() throws FacesException {
        for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
            ExceptionQueuedEvent event = i.next();
            ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
            Throwable t = context.getException();
            if (t instanceof ViewExpiredException) {
                try {
                    FacesContextManager facesContextManager = new FacesContextManager();                   
                    facesContextManager.addRedirectSurviveMessage(facesContextManager.evaluateExpression("#{localizer.localized('SESSION_EXPIRED')}", String.class));
                    facesContextManager.navigateForOutcome(NavigationConstant.SESSION_EXPIRED);
                } finally {
                    i.remove();
                }
            } else if (t instanceof FacesException) {
                Throwable wrapped = t.getCause();
                if (wrapped instanceof ApplicationRuntimeException || wrapped instanceof NullPointerException || wrapped instanceof ELException) {
                    try {
                        FacesContextManager facesContextManager = new FacesContextManager();
                        facesContextManager.addRedirectSurviveMessage(facesContextManager.evaluateExpression("#{localizer.localized('UNEXPECTED_ERROR')}", String.class));
                        facesContextManager.navigateForOutcome(NavigationConstant.REDIRECT_TO_CURRENT_VIEW);
                        LoggingManager loggingManager = new LoggingManager();
                        loggingManager.getMainLogger().error("Unexpected error occurs.", t);
                    } finally {
                        i.remove();
                    }
                }
            }
        }
        // At this point, the queue will not contain any ViewExpiredEvents.
        // Therefore, let the parent handle them.
        getWrapped().handle();
    }
}
